//
// Created by sally on 24-10-27.
//

#include "TimeTask.h"
#include <iostream>
using namespace whq::timer;

TimeTask::TimeTask(const Millseconds &millseconds, Callback_Function&& Func, bool loop_cond,
    std::array<uint8_t, 5>&& cur_slots, tmpoint epoch)
    :atp(AsyncThreadPool::GetInstance()),
    m_callback_function_(std::move(Func)),
    m_task_execute_point_(std::chrono::steady_clock::now()+millseconds),
    m_time_out(millseconds),
    curwheel(0),
    m_start_time(epoch),
    is_loop(loop_cond)
{
    init_task_level(std::move(cur_slots));
}

TimeTask::~TimeTask()
{
}

void TimeTask::init_task_level(const std::array<uint8_t, 5>& cur_slots)
{
    //这是计算当前任务的到期时间
    tmpoint expire = std::chrono::steady_clock::now() + m_time_out;
    uint32_t gap = std::chrono::duration_cast<Millseconds>(expire - m_start_time).count()/TIM_UNIT;
    //上述得到的gap就是多少个刻度，需要将这个刻度映射到时间轮上去
    m_slot_req[0] = FIRST_INDEX(gap);

    for (uint8_t i = 1 ;i < 5; ++i)
    {
        m_slot_req[i] = NTH_INDEX(gap,i);
    }

    //检查当前任务应该处于哪个层级中，如果我存在于这个层级中，并且时间指针，所反映出来的slot和我的当前slot不相等
    //说明，还没有运行到我所处的时间范围内，比如说 我在第2层的 2中，说明我需要主时间轮运行第二圈时，才会接近我的运行时间
    //因此，我需要将我的任务，下放到第一层级中去执行，但是现在主时间轮才运行第一圈，处于第二层的1中，因此不相等，
    //我需要呆在第二层中
    for (int i = 4; i >= 0; i--)
    {
        //cur_slots是主时间轮运动时反映的层级映射关系，这里就是当前层级的时间轮的时间指针还没有推进到我这个索引处，则说明我还是在这一层
        //m_slot_req[i] != 0 这里就是说明，我是属于当前层的，并且当前层的时间指针还没有推进到这，就说明我是需要放在这里的
        //不需要考虑插入的位置在当前时间指针左边的位置，因为左边的位置是我们已经执行完的位置，我们计算的肯定是基于当前时间的
        //未运行的一定是在右边的
        if (m_slot_req[i] != 0 && m_slot_req[i] != cur_slots[i])
        {
            curwheel = i;
            break;
        }
    }
}

void TimeTask::execute()
{
    m_future_bool = atp.add(m_callback_function_);
}

/**
 *
 *
 * @return 当前所在的层级的槽序列就是根据任务的到期时间映射到的相关层的槽序列
 */
std::pair<uint8_t, uint8_t> TimeTask::get_wheel_solt()
{
    //std::lock_guard<std::recursive_mutex> lock(m_mutex_);
     // std::cout<<" curwheel: "<<curwheel<<std::endl;
    return std::make_pair(curwheel,m_slot_req[curwheel]);
}

std::pair<uint8_t, uint8_t> TimeTask::tick()
{
    if (curwheel ==0)
    {
        //如果处于主时间轮，说明当前已经处于最低层的轮子了，没法跳了，需要执行了，则直接返回序号和任务所处的槽位
        return std::make_pair(curwheel,m_slot_req[curwheel]);
    }

    uint8_t next_wheel = 0;
    //判断在本层时间轮之前，该任务是否在之前的时间轮上也具有槽位，如果有则说明下一跳就需要跳到这里
    for (uint8_t i = curwheel -1; i >= 0; --i)
    {
        //当任务添加进入时，会把他在每个层级的索引都计算好，我们检查它是否在前一层具有索引
        //如果有则需要当前i就是任务需要跳到的层级,m_slot_req[i]，就是它所处的索引
        if (m_slot_req[i] != 0)
        {
            next_wheel = i;
            break;
        }
    }
    //需要将任务所处的当前层，往前推进一层，因为这个函数就是推进映射的函数
    curwheel = next_wheel;
    return std::make_pair(curwheel,m_slot_req[curwheel]);
}


